home *** CD-ROM | disk | FTP | other *** search
/ Languguage OS 2 / Languguage OS II Version 10-94 (Knowledge Media)(1994).ISO / gnu / ispell40.lha / ispell-4.0 / build.c < prev    next >
C/C++ Source or Header  |  1993-05-31  |  11KB  |  571 lines

  1. /* Copyright (C) 1990, 1993 Free Software Foundation, Inc.
  2.  
  3.    This file is part of GNU ISPELL.
  4.  
  5.    This program is free software; you can redistribute it and/or modify
  6.    it under the terms of the GNU General Public License as published by
  7.    the Free Software Foundation; either version 2, or (at your option)
  8.    any later version.
  9.  
  10.    This program is distributed in the hope that it will be useful,
  11.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.    GNU General Public License for more details.
  14.  
  15.    You should have received a copy of the GNU General Public License
  16.    along with this program; if not, write to the Free Software
  17.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  18.  
  19. #include <stdio.h>
  20. #include <ctype.h>
  21.  
  22. #ifdef HAVE_MALLOC_H
  23. #include <malloc.h>
  24. #endif
  25.  
  26. #include "ispell.h"
  27. #include "hash.h"
  28. #include "build.h"
  29. #include "getopt.h"
  30.  
  31. int print = 0;
  32.  
  33. #ifndef min
  34. #define min(a,b) ((a)<(b)?(a):(b))
  35. #endif
  36.  
  37.  
  38. unsigned char *tmp_hused, *hused;
  39. #define BITVECSIZE 8192        /* 64K bits */
  40. unsigned short hused_limit;
  41.  
  42. char inbuf[100];
  43. comp_char outbuf[100];
  44. struct hash_table_entry hte;
  45.  
  46. #ifdef __STDC__
  47.  
  48. unsigned short parse_flags (comp_char *, char *);
  49. hash_index find_slot (hash_index);
  50. void toomanywords (void);
  51. void mklextbl (char *, FILE *);
  52. void hash_write (FILE *);
  53. void hash_awrite (FILE *);
  54. void hash_ewrite (FILE *);
  55. int lexword (char *, int, unsigned char *);
  56. void set_bitvec (unsigned char *, unsigned short);
  57.  
  58. #else
  59.  
  60. extern unsigned short parse_flags ();
  61. extern hash_index find_slot ();
  62. extern void toomanywords ();
  63. extern void hash_write ();
  64. extern void hash_awrite ();
  65. extern void hash_ewrite ();
  66. extern int lexword ();
  67.  
  68. #endif
  69.  
  70. int binary_flag = 0;
  71. int ascii_flag = 0;
  72. int reap_flag = 0;
  73. int debug_flag = 0;
  74.  
  75. char buildout[100];
  76.  
  77. /* this array contains letters to use when generating near misses */
  78. char near_miss_letters[256];
  79. int nnear_miss_letters;
  80.  
  81. /* this array has 1 for any character that is in near_miss_letters */
  82. char near_map[256];
  83.  
  84. int
  85. main (argc, argv)
  86.   int argc;
  87.   char **argv;
  88. {
  89.   FILE *in;
  90. #ifdef __STDC__
  91.   void reapall (void);
  92. #else
  93.   extern void reapall ();
  94. #endif
  95.   int c;
  96.   extern char *optarg;
  97.   extern int optind;
  98.   char *name;
  99.   char *freqfile = NULL;
  100.  
  101.   buildout[0] = 0;
  102.  
  103.   while ((c = getopt (argc, argv, "prbao:f:d")) != EOF)
  104.     {
  105.       switch (c)
  106.     {
  107.     case 'd':
  108.       debug_flag = 1;
  109.       break;
  110.     case 'f':
  111.       freqfile = optarg;
  112.       break;
  113.     case 'p':
  114.       print = 1;
  115.       break;
  116.     case 'r':
  117.       reap_flag = 1;
  118.       break;
  119.     case 'b':
  120.       binary_flag = 1;
  121.       break;
  122.     case 'a':
  123.       ascii_flag = 1;
  124.       break;
  125.     case 'o':
  126.       (void) strcpy (buildout, optarg);
  127.       break;
  128.     default:
  129.       /* message printed by getopt */
  130.       exit (1);
  131.     }
  132.     }
  133.  
  134.   if (freqfile == NULL)
  135.     {
  136.       (void) fprintf (stderr, "no freq file specified\n");
  137.       exit (1);
  138.     }
  139.   name = argv[optind];
  140.  
  141.   if (binary_flag == 0 && ascii_flag == 0)
  142.     {
  143.       (void) fprintf (stderr, "must have either -a or -b\n");
  144.       exit (1);
  145.     }
  146.  
  147.   if (debug_flag)
  148.     {
  149.       mklextbl (freqfile, stdout);
  150.       exit (0);
  151.     }
  152.  
  153.   mklextbl (freqfile, (FILE *) NULL);
  154.  
  155.   if ((in = fopen (name, "r")) == NULL)
  156.     {
  157.       (void) fprintf (stderr, "can't open %s\n", name);
  158.       exit (1);
  159.     }
  160.  
  161.   build (in);
  162.  
  163.   (void) fclose (in);
  164.  
  165.   if (reap_flag)
  166.     reapall ();
  167.  
  168.   if (binary_flag)
  169.     {
  170.       if (buildout[0] == 0)
  171.     {
  172.       strcpy (buildout, name);
  173.       strcat (buildout, ".hsh");
  174.     }
  175.       write_binary (buildout);
  176.     }
  177.  
  178.   if (ascii_flag)
  179.     {
  180.       if (buildout[0] == 0)
  181.     {
  182.       strcpy (buildout, name);
  183.       strcat (buildout, ".f");
  184.     }
  185.       write_ascii (buildout);
  186.     }
  187.   return (0);
  188. }
  189.  
  190.  
  191. void
  192. write_binary (name)
  193.   char *name;
  194. {
  195.   FILE *out;
  196.   char *mode;
  197.  
  198. #ifdef MSDOS
  199.   mode = "wb";
  200. #else
  201.   mode = "w";
  202. #endif
  203.   if ((out = fopen (name, mode)) == NULL)
  204.     {
  205.       (void) fprintf (stderr, "can't create %s\n", name);
  206.       exit (1);
  207.     }
  208.   hash_write (out);
  209.  
  210.   fclose (out);
  211. }
  212.  
  213.  
  214. void
  215. write_ascii (name)
  216.   char *name;
  217. {
  218.   FILE *out;
  219.  
  220.   if ((out = fopen (name, "w")) == NULL)
  221.     {
  222.       (void) fprintf (stderr, "can't create %s\n", name);
  223.       exit (1);
  224.     }
  225.  
  226.   hash_awrite (out);
  227.  
  228.   if (ferror (out))
  229.     {
  230.       (void) fprintf (stderr, "error writing %s\n", name);
  231.       exit (1);
  232.     }
  233.  
  234.   fclose (out);
  235. }
  236.  
  237.  
  238. void
  239. build (in)
  240.   FILE *in;
  241. {
  242.   int len;
  243.   struct hash_table_entry *htep;
  244.   unsigned short nwords = 0;
  245.   int i;
  246.   hash_index h, prev_hindex;
  247.   char *p;
  248.   unsigned short flags;
  249.   unsigned short strsize = 0;
  250. #ifdef __STDC__
  251.   unsigned short nextprime (unsigned short);
  252. #else
  253.   extern unsigned short nextprime ();
  254. #endif
  255.  
  256.   tmp_hused = (unsigned char *) xcalloc (1, BITVECSIZE);
  257.  
  258.   (void) fprintf (stderr, "Counting words: ");
  259.   while (fgets (inbuf, (int) sizeof inbuf, in) != NULL)
  260.     {
  261.       if (inbuf[0] == '#')
  262.     continue;
  263.       p = (char *) strchr (inbuf, '/');
  264.       if (p)
  265.     *p = 0;
  266.       p = (char *) strchr (inbuf, '\n');
  267.       if (p)
  268.     *p = 0;
  269.       if (inbuf[0] == 0)
  270.     continue;
  271.       if (strlen (inbuf) >= MAX_WORD_LEN)
  272.     {
  273.       (void) fprintf (stderr, "warning: %s too long\n", inbuf);
  274.       continue;
  275.     }
  276.       len = lexword (inbuf, strlen (inbuf), outbuf);
  277.       if (len == 0)
  278.     {
  279.       (void) fprintf (stderr,
  280.               "%s can't be compressed; try re-running 'freq'\n",
  281.               inbuf);
  282.       continue;
  283.     }
  284.       if (nwords >= HASH_SPECIAL - 1)
  285.     toomanywords ();
  286.       if ((nwords % 1000) == 0)
  287.     {
  288.       (void) fprintf (stderr, "%u ", nwords);
  289.       (void) fflush (stderr);
  290.     }
  291.       nwords++;
  292.       if (len > sizeof hte.u.s.data)
  293.     strsize += len - sizeof hte.u.l.data;
  294.       h = hash ((char *) outbuf);
  295.       set_bitvec (tmp_hused, h);
  296.     }
  297.   nwords++;            /* add one since slot 0 is reserved */
  298.  
  299.   (void) fprintf (stderr, "%u words\n", nwords);
  300.   hashsize = nextprime (nwords);
  301.   if (hashsize >= HASH_SPECIAL)
  302.     toomanywords ();
  303.  
  304.   hused_limit = (hashsize + 7) >> 3;
  305.   hused = (unsigned char *) xcalloc (1, hused_limit);
  306.  
  307.   /* make the slots that were introduced when rounding up
  308.      * by 8 be busy
  309.      */
  310.   for (h = hashsize; h < hused_limit * 8; h++)
  311.     set_bitvec (hused, h);
  312.   for (i = 0, h = 0; i < BITVECSIZE; i++)
  313.     {
  314.       unsigned char x = tmp_hused[i];
  315.       unsigned short bit;
  316.  
  317.       for (bit = 1; bit != 0x100; bit <<= 1, h++)
  318.     {
  319.       if (x & bit)
  320.         {
  321.           hash_index real_hash = h % hashsize;
  322.           set_bitvec (hused, real_hash);
  323.         }
  324.     }
  325.     }
  326.   /* now hused has 1 where ever something will hash to */
  327.  
  328.   free ((char *) tmp_hused);
  329.   tmp_hused = NULL;
  330.  
  331.   alloc_tables ((long) hashsize, (long) strsize);
  332.  
  333.   set_bitvec (hused, 0);
  334.   htep = (struct hash_table_entry *) xcalloc (1, sizeof *htep);
  335.   htep->next = HASH_END;
  336.   hash_store (0, htep);
  337.   free ((char *) htep);
  338.  
  339.   rewind (in);
  340.  
  341.   (void) fprintf (stderr, "Starting hash: ");
  342.   nwords = 0;
  343.   while (fgets (inbuf, (int) sizeof inbuf, in) != NULL)
  344.     {
  345.       if ((nwords % 1000) == 0)
  346.     {
  347.       (void) fprintf (stderr, "%u ", nwords);
  348.       (void) fflush (stderr);
  349.     }
  350.       nwords++;
  351.       flags = 0;
  352.       p = (char *) strchr (inbuf, '/');
  353.       if (p)
  354.     {
  355.       flags = parse_flags (inbuf, p);
  356.       *p = 0;
  357.     }
  358.       p = (char *) strchr (inbuf, '\n');
  359.       if (p)
  360.     *p = 0;
  361.       if (inbuf[0] == 0)
  362.     continue;
  363.       if (strlen (inbuf) >= MAX_WORD_LEN)
  364.     continue;
  365.       len = lexword (inbuf, strlen (inbuf), outbuf);
  366.       if (len == 0)
  367.     continue;
  368.       h = hash ((char *) outbuf) % hashsize;
  369.       if (print)
  370.     (void) printf ("%s hash %u; ", inbuf, h);
  371.       if (!hash_emptyp (h))
  372.     {
  373.       if (print)
  374.         (void) printf ("already used ");
  375.       prev_hindex = hash_find_end (h);
  376.       if (print)
  377.         (void) printf ("tail %u; ", prev_hindex);
  378.       h = find_slot (prev_hindex);
  379.       if (print)
  380.         (void) printf ("new slot %u; ", h);
  381.       hash_set_next (prev_hindex, h);
  382.     }
  383.       htep = make_hash_table_entry (outbuf, len);
  384.       hash_store (h, htep);
  385.       store_flags (h, flags);
  386.       if (print)
  387.     (void) printf ("\n");
  388.     }
  389.   (void) printf ("\n");
  390.   free ((char *) hused);
  391. }
  392.  
  393. void
  394. toomanywords ()
  395. {
  396.   (void) fprintf (stderr, "too many words, max = %u\n", HASH_SPECIAL - 1);
  397.   exit (1);
  398. }
  399.  
  400. #if 0
  401. get_bitvec (bitvec, n)
  402.      unsigned char *bitvec;
  403.      unsigned short n;
  404. {
  405.   static unsigned char bittbl[] =
  406.   {1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80};
  407.  
  408.   return (bitvec[n >> 3] & bittbl[n & 7]);
  409. }
  410.  
  411. #endif
  412.  
  413. /*
  414.  * this can return free slot that will not be used as the start of a
  415.  * hash chain.  It tries to find a slot on the same page,
  416.  * but I've not measured it to see if that helps.
  417.  */
  418. hash_index
  419. find_slot (hindex)
  420.   hash_index hindex;
  421. {
  422.   int start;
  423.   int i;
  424.   int x, bit, n;
  425.  
  426.   if (hindex >= hashsize)
  427.     {
  428.       (void) fprintf (stderr, "bad index to find_slot %x %x\n",
  429.               hindex, hashsize);
  430.       exit (1);
  431.     }
  432.   /* round down to beginning of page: 128 entries per 1K page */
  433.   start = (hindex & ~127) >> 3;
  434.   i = start;
  435.   while (1)
  436.     {
  437.       x = hused[i];
  438.       if (x != 0xff)
  439.     {
  440.       for (bit = 1, n = 0; bit < 0x100; bit <<= 1, n++)
  441.         {
  442.           if ((x & bit) == 0)
  443.         {
  444.           hused[i] |= bit;
  445.           hindex = i * 8 + n;
  446.           if (hindex >= hashsize)
  447.             {
  448.               (void) fprintf (stderr,
  449.                       "find_slot r bad %x\n",
  450.                       hindex);
  451.               exit (1);
  452.             }
  453.           return (hindex);
  454.         }
  455.         }
  456.       (void) fprintf (stderr, "hash table error\n");
  457.       exit (1);
  458.     }
  459.       i++;
  460.       if (i >= hused_limit)
  461.     i = 0;
  462.       if (i == start)
  463.     {
  464.       (void) fprintf (stderr, "hused table overflow??\n");
  465.       exit (1);
  466.     }
  467.     }
  468.   /* NOTREACHED */
  469. }
  470.  
  471. struct hash_table_entry *
  472. make_hash_table_entry (string, len)
  473.   comp_char *string;
  474.   int len;
  475. {
  476.   static struct hash_table_entry e;
  477.   comp_char *p;
  478.   int i;
  479.   e.next = HASH_END;
  480.   if (len <= sizeof e.u.s.data)
  481.     {
  482.       (void) strncpy ((char *) e.u.s.data,
  483.               (char *) string,
  484.               (int) sizeof e.u.s.data);
  485.       return (&e);
  486.     }
  487.   else
  488.     {
  489.       e.u.l.short_flag = 0;
  490.       e.u.l.len = (unsigned char) len;
  491.       p = e.u.l.data;
  492.       for (i = 0; i < sizeof e.u.l.data; i++)
  493.     *p++ = *string++;
  494.       e.u.l.sindex =
  495.     copy_out_string (string, len - sizeof e.u.l.data);
  496.       return (&e);
  497.     }
  498. }
  499.  
  500. unsigned short
  501. parse_flags (word, p)
  502.   comp_char *word;
  503.   char *p;
  504. {
  505.   unsigned short flags = 0;
  506.   int c;
  507.  
  508.   while (*p && *p != '\n')
  509.     {
  510.       if (*p != '/')
  511.     goto error;
  512.       c = *p++;
  513.       if (isupper (c))
  514.     c = tolower (c);
  515.  
  516.       switch (*p)
  517.     {
  518.     case 'v':
  519.       flags |= V_FLAG;
  520.       break;
  521.     case 'n':
  522.       flags |= N_FLAG;
  523.       break;
  524.     case 'x':
  525.       flags |= X_FLAG;
  526.       break;
  527.     case 'h':
  528.       flags |= H_FLAG;
  529.       break;
  530.     case 'y':
  531.       flags |= Y_FLAG;
  532.       break;
  533.     case 'g':
  534.       flags |= G_FLAG;
  535.       break;
  536.     case 'j':
  537.       flags |= J_FLAG;
  538.       break;
  539.     case 'd':
  540.       flags |= D_FLAG;
  541.       break;
  542.     case 't':
  543.       flags |= T_FLAG;
  544.       break;
  545.     case 'r':
  546.       flags |= R_FLAG;
  547.       break;
  548.     case 'z':
  549.       flags |= Z_FLAG;
  550.       break;
  551.     case 's':
  552.       flags |= S_FLAG;
  553.       break;
  554.     case 'p':
  555.       flags |= P_FLAG;
  556.       break;
  557.     case 'm':
  558.       flags |= M_FLAG;
  559.       break;
  560.     default:
  561.       goto error;
  562.     }
  563.       p++;
  564.     }
  565.   return (flags);
  566.  
  567. error:
  568.   (void) fprintf (stderr, "Syntax error: %s\n", word);
  569.   return (flags);
  570. }
  571.